namespace SimpleWebServices.Web.Routing
{
    using System;
    using System.Web;
    using System.Web.Mvc;
    using System.Web.Routing;
    using SimpleWebServices.Data;
    using SimpleWebServices.Web.Mvc;

    public sealed class ResourceRoute<T> : RouteBase
        where T : IRecord
    {
        private Type _controller;

        public ResourceRoute(Type controller)
        {
            this.Controller = controller;
        }

        public Type Controller
        {
            get
            {
                return this._controller;
            }

            set
            {
                if (null == value)
                {
                    throw new ArgumentNullException("value");
                }
                else if (!value.IsSubclassOf(typeof(Controller)))
                {
                    throw new ArgumentOutOfRangeException("value");
                }

                this._controller = value;
            }
        }

        public override RouteData GetRouteData(HttpContextBase httpContext)
        {
            RouteData result = null;

            Route route = this.GetRoute(httpContext);
            if (null != route)
            {
                result = route.GetRouteData(httpContext);
            }

            return result;
        }

        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
        {
            if (null == requestContext)
            {
                throw new ArgumentNullException("requestContext");
            }

            VirtualPathData result = null;

            Route route = this.GetRoute(requestContext.HttpContext);
            if (null != route)
            {
                result = route.GetVirtualPath(requestContext, values);
            }

            return result;
        }

        private Route GetRoute(HttpContextBase httpContext)
        {
            if (null == httpContext)
            {
                throw new ArgumentNullException("httpContext");
            }

            Route result = null;

            IControlResource<T> controller = Activator.CreateInstance(this.Controller) as IControlResource<T>;
            if (null != controller)
            {
                AbsoluteUri urn = controller.Converter.Urn;
                if (null != urn)
                {
                    if (Record.Exists<T>(urn))
                    {
                        result = this.New(httpContext.Request.Path);
                    }
                }
            }

            return result;
        }

        private Route New(ResourcePath path)
        {
            string language = string.Empty;
            string action = null;

            string controller = this.Controller.Name;
            if (controller.EndsWith("Controller", StringComparison.OrdinalIgnoreCase))
            {
                controller = controller.Substring(0, controller.Length - "Controller".Length);
            }

            if (string.IsNullOrEmpty(path.Language))
            {
                action = "LanguageNegotiation";
            }
            else
            {
                language = path.Language;
                if (string.IsNullOrEmpty(path.Extension))
                {
                    action = "ContentNegotiation";
                }
                else
                {
                    foreach (var method in this.Controller.GetMethods())
                    {
                        foreach (object attribute in method.GetCustomAttributes(typeof(ContentNegotiationAttribute), true))
                        {
                            var conneg = attribute as ContentNegotiationAttribute;
                            if (conneg.Extension.Equals(path.Extension, StringComparison.OrdinalIgnoreCase))
                            {
                                action = method.Name;
                                break;
                            }
                        }

                        if (null != action)
                        {
                            break;
                        }
                    }
                }
            }

            return new Route(path, new MvcRouteHandler())
            {
                Defaults = new RouteValueDictionary(new { controller = controller, action = action, language = language }),
                Constraints = new RouteValueDictionary()
            };
        }
    }
}